package com.zwp.base.uitls

import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.internal.`$Gson$Types`
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter

class GsonDefaultAdapterFactory : TypeAdapterFactory {

    override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
        if (type.type == String::class.java) {
            return createStringAdapter()
        }
        if (type.rawType == List::class.java || type.rawType == Collection::class.java) {
            return createCollectionAdapter(type, gson)
        }
        return null
    }


    private fun <T : Any> createCollectionAdapter(
        type: TypeToken<T>,
        gson: Gson
    ): TypeAdapter<T>? {
        val rawType = type.rawType
        if (!Collection::class.java.isAssignableFrom(rawType)) {
            return null
        }

        val elementType = `$Gson$Types`.getCollectionElementType(type.type, rawType)
        val elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType)) as TypeAdapter<Any>

        return object : TypeAdapter<Collection<Any>>() {
            override fun write(out: JsonWriter, value: Collection<Any>?) {
                out.beginArray()
                value?.forEach {
                    elementTypeAdapter.write(out, it)
                }
                out.endArray()
            }

            override fun read(reader: JsonReader): Collection<Any> {
                val list = mutableListOf<Any>()
                if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    return list
                }
                reader.beginArray()
                while (reader.hasNext()) {
                    val element = elementTypeAdapter.read(reader)
                    list.add(element)
                }
                reader.endArray()
                return list
            }
        } as TypeAdapter<T>
    }

    private fun <T : Any> createStringAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<String>() {
            override fun write(out: JsonWriter, value: String?) {
                out.value(value ?: "")
            }

            override fun read(`in`: JsonReader): String {
                `in`.let {
                    if (it.peek() == JsonToken.NULL) {
                        return ""
                    }
                    return it.nextString()
                }
            }

        } as TypeAdapter<T>
    }
}